package cn.wolfcode.shop.service.impl;

import cn.wolfcode.shop.domain.User;
import cn.wolfcode.shop.exception.GlobalException;
import cn.wolfcode.shop.mapper.UserMapper;
import cn.wolfcode.shop.redis.RedisServer;
import cn.wolfcode.shop.redis.UserKeyPrefix;
import cn.wolfcode.shop.result.CodeMsg;
import cn.wolfcode.shop.service.IUserService;
import cn.wolfcode.shop.util.IdGenerateUtil;
import cn.wolfcode.shop.util.MD5Util;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.UUID;

@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisServer redisServer;

    @Override
    public User getById(Long id) {
        User user = redisServer.get(UserKeyPrefix.USER, "" + id, User.class);
        //如果缓存中存在当前key对应的user
        if (user != null) {
            if (user.getId() == null) {
            //如果该user是空的对象,则说明上一次查询数据库中没有该id用户,往redis存放的空对象
                return null;
            }
            return user;
        }
        //用来判断解锁人是否是上锁人
        String requestId = IdGenerateUtil.get().nextId() + "";
        //获取锁在一定时间内  通过setNx如果key在redis中存在,设置失败,来表示当前被锁
        boolean haveLock = redisServer.tryGetDistributedLock(UserKeyPrefix.USER_LOCK+":"+ id, requestId, 10);
        //当前被锁时,不操作
        if (!haveLock) {
            return null;
        }
        //从数据库中查询此id用户
        user = userMapper.getById(id);
        if (user == null) {
            //如果通过请求id查询用户不存在,则将空的对象缓存一定时间,下次再使用相同id访问直接从缓存中获取空对象,不再查询数据库
            redisServer.set(UserKeyPrefix.USER_NULL, "" + id, new User());
        } else {
            redisServer.set(UserKeyPrefix.USER, "" + id, user);
        }
        //操作完毕 释放锁
        redisServer.releaseDistributedLock(UserKeyPrefix.USER_LOCK +":"+ id, requestId);
        return user;
}

    @Override
    public String login(Long mobile, String password) throws GlobalException {
        User user = userMapper.getById(mobile);
        if (user == null) {
            throw new GlobalException(CodeMsg.ACCOUNT_NOT_EXIST);
        }
        //判断当前密码再次 加当前用户的盐 加密后 是否匹配数据库密码
        String dbPass = MD5Util.formPassToDbPass(password, user.getSalt());
        if (!dbPass.equals(user.getPassword())) {
            throw new GlobalException(CodeMsg.LOGIN_FAIL);
        }
        //token+cookie方式代替session
        //存放在redis中的key=前缀 + token value = user对象 cookie中存放token 请求中cookie提交token,
        //获取redis中的value cookie中的 前缀+token
        String token = create(user);
        return token;
    }

    /**
     * 创建一个token 作为cookie的value 来响应给浏览器
     * 将UserKeyPrefix.USER_TOKEN 这个常量作为前缀,拼接上随机生成的UUID  作为存储在redis中的key
     * 将User对象存储在redis中的 这个key中
     *
     * @param user
     * @return
     */
    private String create(User user) {
        //将随机的UUID变成字符串并去掉-
        String token = UUID.randomUUID().toString().replace("-", "");
        //调用set方法将user通过set方法规则存储到redis中
        redisServer.set(UserKeyPrefix.USER_TOKEN, token, user);
        //将token返回,用于用户的令牌 来通过拼接指定的前缀去redis中回去存储的值
        return token;
    }
}
